/*
 *    This file is part of SSHTunneler.
 *
 *    Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
 *
 *    SSHTunneler is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    SSHTunneler is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with SSHTunneler.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
package sshtunneler.client.ssh;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.JOptionPane;

import sshtunneler.client.SSHTunnelerApp;
import sshtunneler.client.data.Config;
import sshtunneler.library.Server;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class SSHConnectionContainer {

	/************ SINGLETON ****************/
	public static SSHConnectionContainer inst = new SSHConnectionContainer();

	private SSHConnectionContainer() {
		this.jsch = new JSch();
		this.connections = new ArrayList<SSHConnection>();
	}

	/************** INST *******************/
	private JSch jsch;
	private List<SSHConnection> connections;
	private HashMap<SSHConnection, SSHConnectionWatcher> watchers = new HashMap<SSHConnection, SSHConnectionWatcher>();

	public boolean hasConnectionTo(Server server) {
		for (SSHConnection conn : this.connections) {
			if (conn.getServer().equals(server)) {
				return true;
			}
		}
		return false;
	}

	public SSHConnection getConnectionTo(Server server) {

		for (SSHConnection conn : this.connections) {
			if (conn.getServer().equals(server)) {
				return conn;
			}
		}

		return null;
	}

	void watcher_callback(SSHConnection disconnected) {
		Server s = disconnected.getServer();
		JOptionPane.showMessageDialog(null,
				"You got disconnected from server: " + s);

		disconnected.close();
		this.connections.remove(disconnected);
		this.watchers.remove(disconnected);

		SSHTunnelerApp.getApplication().getMainFrame().refresh_tree();
	}

	public SSHConnection connectTo(Server server) {
		if (this.hasConnectionTo(server)) {
			return this.getConnectionTo(server);
		}

		String user = server.getUsername();
		String host = server.getHostname();
		int port = server.getPort();

		if (user.equals("")) {
			user = Config.default_username;
		}

		try {
			Session session = this.jsch.getSession(user, host, port);

			SSHUserData data = new SSHUserData(server);
			session.setUserInfo(data);

			session.connect();

			if (session.isConnected()) {
				SSHConnection newConnection = new SSHConnection(server, data,
						session);
				SSHConnectionWatcher watcher = new SSHConnectionWatcher(
						newConnection);

				this.connections.add(newConnection);
				this.watchers.put(newConnection, watcher);
				watcher.start();
				return newConnection;
			} else {
				return null;
			}
		} catch (JSchException ex) {
			Logger.getLogger(SSHConnectionContainer.class.getName()).log(
					Level.SEVERE, null, ex);
			JOptionPane.showMessageDialog(null, ex.getMessage());
		}

		return null;
	}

	public void closeConnectionTo(Server server) {
		if (!this.hasConnectionTo(server)) {
			return;
		}
		SSHConnection connection = this.getConnectionTo(server);
		SSHConnectionWatcher watcher = this.watchers.get(connection);

		watcher.interrupt();
		connection.close();
		this.connections.remove(connection);
		this.watchers.remove(connection);
	}
}
